#!/usr/bin/env python
# -*- coding: UTF-8 -*-

# Magpie - an open source discussion forum system.
#
# Copyright (C) 2009 The Magpie Team
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.

import logging, random

from ajiaojr.commons.appengine import counter
from ajiaojr.commons.django.shortcuts import render_to_response

from ajiaojr.magpie import forms, models

from django.http import Http404
from django.http import HttpResponseForbidden
from django.http import HttpResponseNotFound
from django.http import HttpResponseRedirect
from django.http import HttpResponseServerError
from django.template import Context, loader
from django.utils.translation import ugettext as _

from google.appengine.api import memcache, users
from google.appengine.ext import db

def build_template_params(title, uri, user=None):
  club_config = models.ClubConfig.get_instance()
  params = {
            'club_config': club_config,
            'title_string': title,
            'current_club_user': user,
            'user_control_string': __user_control_string(uri),
            'mine_dropped': False,
            'time_zone': 'UTC',
            }
  
  mine_gold_config = models.MineGoldConfig.get_instance()
  if mine_gold_config.is_enabled:
    rand_int = random.randint(1, mine_gold_config.drop_rate_denominator)
  
  if user:
    params['time_zone'] = user.time_zone
    
    if mine_gold_config.is_enabled:
      if user.mine_dropped:
        params['mine_dropped'] = True
      elif rand_int <= mine_gold_config.drop_rate_numerator:
        user.mine_dropped = True
        user.put()
        params['mine_dropped'] = True
    
  return params

def __user_control_string(uri):
  if users.get_current_user():
    control_string = ("<a href=\"%s\">%s</a>" % (users.create_logout_url(uri),
                                               _("Sign Out")))
  else:
    control_string = ("<a href=\"%s\">%s</a>" % (users.create_login_url(uri),
                                               _("Sign In")))
  return control_string

####################################
# Decorators
####################################

def club_enabled_required(func):
  """
  Decorator that gives an error page if the club is disabled.
  """
  def club_enabled_wrapper(request, *args, **kwds):
    club_config = models.ClubConfig.get_instance()
    if not club_config.is_enabled and not request.admin_mode:
      return HttpResponseForbidden("<h1>Access Denied</h1>")
    return func(request, *args, **kwds)
  return club_enabled_wrapper

def club_writable_required(func):
  """
  Decorator that gives an error page if the club isn't writable
  """
  def club_writable_wrapper(request, *args, **kwds):
    club_config = models.ClubConfig.get_instance()
    if (((not club_config.is_enabled) or (club_config.is_read_only))
        and not request.admin_mode):
      return HttpResponseForbidden("<h1>Access Denied</h1>")
    return func(request, *args, **kwds)
  return club_writable_wrapper

def forum_moderator_required(func):
  """
  Decorator that makes sure that the current user is a forum moderator
  """
  def forum_moderator_wrapper(request, *args, **kwds):
    if ((not request.forum.is_moderator(request.user))
        and (not request.admin_mode)):
      return HttpResponseForbidden("<h1>Access Denied</h1>")
    
    return func(request, *args, **kwds)
  return forum_moderator_wrapper

def forum_required(func):
  """
  Decorator that ensures that the required forum can be found
  """
  def forum_wrapper(request, forum_id, *args, **kwds):
    forum = models.Forum.get_by_id(int(forum_id))
    if forum is None:
      raise Http404
    
    request.forum = forum
    return func(request, forum_id, *args, **kwds)
  
  return forum_wrapper

def forum_readable_required(func):
  """
  Decorator that ensures the forum is readable by the user.
  """
  def forum_readable_wrapper(request, *args, **kwds):
    if not (request.forum.is_public
            and request.forum.forum_category.is_public):
      if ((request.user is None)
          or (not request.forum.user_can_read(request.user))):
        return HttpResponseForbidden("<h1>Access Denied</h1>")
    return func(request, *args, **kwds)
  return forum_readable_wrapper
  
def forum_writable_required(func):
  """
  Decorator that ensures that the required forum can be writen to
  """
  def forum_writable_wrapper(request, *args, **kwds):
    if not request.forum.user_can_write(request.user):
       return HttpResponseForbidden("<h1>Access Denied</h1>")
    return func(request, *args, **kwds)
  return forum_writable_wrapper

def post_required(func):
  """
  Decorator that ensures that the required post can be found
  """
  def post_wrapper(request, post_id, *args, **kwds):
    post = models.ForumPost.get_by_id(int(post_id))
    if post is None:
      raise Http404
    
    forum = post.forum
    
    if not (forum.is_public and forum.forum_category.is_public):
      if (request.user is None) or (not forum.user_can_read(request.user)):
        return HttpResponseForbidden("<h1>Access Denied</h1>")
    
    request.post = post
    request.forum = post.forum
    
    return func(request, post_id, *args, **kwds)
  return post_wrapper

def post_writable_required(func):
  """
  Decorator that ensures that a post can be updated
  """
  def post_writable_wrapper(request, *args, **kwds):
    root_post = request.post.root_post
    if root_post is None:
      root_post = request.post
    
    if root_post.is_locked:
      if not (request.forum.is_moderator(request.user) or
                                    request.admin_mode):
        return HttpResponseForbidden("<h1>Access Denied</h1>")
    
    return func(request, *args, **kwds)
  return post_writable_wrapper

def pm_enabled_required(func):
  """Decorator that ensures that the PM functionality is enabled
  """
  def pm_enabled_wrapper(request, *args, **kwds):
    club_config = models.ClubConfig.get_instance()
    if not club_config.is_pm_enabled:
      return HttpResponseForbidden("<h1>Access Denied</h1>")
    return func(request, *args, **kwds)
  return pm_enabled_wrapper

def pm_required(func):
  """Decorator that ensures that the PM can be found
  """
  def pm_required_wrapper(request, message_id, *args, **kwds):
    pm = models.PrivateMessage.get_by_id(int(message_id))
    if pm is None:
      raise Http404
    
    request.pm = pm
    
    return func(request, message_id, *args, **kwds)
  return pm_required_wrapper

def pm_writable_required(func):
  """Decorator that ensures that the PMs can be read
  """
  def pm_writable_wrapper(request, *args, **kwds):
    club_config = models.ClubConfig.get_instance()
    if (not club_config.is_pm_enabled) or club_config.is_pm_read_only:
      return HttpResponseForbidden("<h1>Access Denied</h1>")
    return func(request, *args, **kwds)
  return pm_writable_wrapper

####################################
# Views
####################################
def about(request):
  p = build_template_params(_('About'), request.get_full_path(), request.user)
  return render_to_response(request, 'about.html', p)

@club_enabled_required
def left(request):
  p = build_template_params(_('Left'),
                              request.get_full_path(),
                              request.user)
  
  if request.user is not None:
    p['favourites'] = request.user.get_favourites()
    
  p['categories'] = models.ForumCategory.get_forum_tree()
  return render_to_response(request, 'left.html', p)

def main_view(request):
  p = build_template_params(_('Main View'),
                              request.get_full_path(),
                              request.user)
  return render_to_response(request, 'main.html', p)

def page_not_found(request):
  t = loader.get_template('404.html')
  p = build_template_params(_('Not Found???!1!!?'),
                              request.get_full_path(),
                              request.user)
  return HttpResponseNotFound(t.render(Context(p)))

@club_writable_required
def profile(request):
  if request.method == 'POST':
    f = forms.ClubUserForm(request.POST, instance = request.user)
    if f.is_valid():
      f.save()
      return HttpResponseRedirect('/right.php')
  else:
    f = forms.ClubUserForm(instance = request.user)

  p = build_template_params(_('Profile'),
                              request.get_full_path(),
                              request.user)
  p['form'] = f
  return render_to_response(request, 'user/profile.html', p)

@club_enabled_required
def right(request):
  p = build_template_params(_('Welcome'),
                              request.get_full_path(),
                              request.user)
  return render_to_response(request, 'right.html', p)

def server_error(request):
  t = loader.get_template('500.html')
  p = build_template_params(_('OMG!1! Internal Server Error!!!1one'),
                              request.get_full_path(), request.user)
  return HttpResponseServerError(t.render(Context(p)))

@club_enabled_required
@post_required
def thread(request, post_id, starting_index = None):
  if starting_index == '':
    starting_index = None
    
  if starting_index is None:
    replies, next_id = request.post.get_all_replies(None, 49)
  else:
    replies, next_id = request.post.get_all_replies(int(starting_index), 50)

  p = build_template_params(_('View Thread'), '/', request.user)
  if next_id is not None:
    p['next_index'] = next_id
    
  if starting_index is None:
    p['post'] = request.post
    counter.increment('THREAD_READS:'+str(request.post.key().id()))

  if request.user is not None:
    if (users.is_current_user_admin()
        or request.post.forum.is_moderator(request.user)):
      p['admin_mode']=True
    
  p['forum'] = request.forum
  p['replies'] = replies
  return render_to_response(request, 'post/thread.html', p)

@club_enabled_required
def user(request, key_name):
  """Generates the user information view.
  
  Args:
    key_name: the key name that uniquely identifies the user.
  
  Returns:
    A HttpResponse instance with all the user information.
  """
  user = models.ClubUser.get_by_key_name(key_name)
  if user is None:
    raise Http404

  p = build_template_params(_('User Information'),
                              request.get_full_path(), request.user)
  p['user'] = user
  return render_to_response(request, 'user/info.html', p)
